package com.simple.dsrouter.strategy.impl;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.PatternMatchUtils;

import com.simple.dsrouter.config.DataSourceConfig;
import com.simple.dsrouter.strategy.RouteStrategy;
import com.simple.dsrouter.util.ValidateUtils;

public abstract class AbstractRouteStrategy implements RouteStrategy {

	/**
	 * 分组id和数据源的映射。id从零开始，依次递增
	 * */
	protected Map<Integer, List<DataSourceConfig>> dataSourceKeyMap;

	/**
	 * 不执行路由的方法列表，采用正则表达式匹配，仅支持*
	 * */
	private List<String> excludeMethodPatterns;

	/**
	 * logger
	 * */
	protected Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 过滤方法列表，对于列表中的方法不执行路由
	 * */
	public void route(Object target, Method method, Object[] args) {
		boolean needRoute = true;
		if (excludeMethodPatterns != null) { // 判断是否需要执行路由
			String methodName = method.getName();
			for (String pattern : excludeMethodPatterns) {
				if (PatternMatchUtils.simpleMatch(pattern, methodName)) {
					needRoute = false;
					break;
				}
			}
		}
		if (needRoute) {
			this.executeRoute(target, method, args);
		} else {
			if (logger.isDebugEnabled()) {
				logger.debug(method.getName() + " match excludeMethodPatterns for routing, no routing for this method");
			}
		}
	}

	/**
	 * 对于需要执行路由的方法执行路由
	 * */
	public abstract void executeRoute(Object target, Method method, Object[] args);

	/**
	 * 设置不需要执行路由的方法列表，仅支持这几种形式 "xxx*"，"*xxx" and "*xxx*"，不支持"x**x"
	 * */
	public void setExcludeMethodPatterns(List<String> excludeMethodPatterns) {
		this.excludeMethodPatterns = ValidateUtils.validInterceptMethodPatterns(excludeMethodPatterns);
	}

	/**
	 * 设置数据源分组map
	 * */
	public void setDataSourceKeyMap(Map<Integer, List<DataSourceConfig>> dataSourceKeyMap) {
		if (dataSourceKeyMap == null) {
			throw new IllegalArgumentException("dataSourceKeyMap arugment must not be null");
		}
		if (dataSourceKeyMap.size() <= 0) {
			throw new IllegalArgumentException("dataSourceKeyMap size must be big than zero");
		}
		// check each
		for (int i = 0; i < dataSourceKeyMap.size(); i++) {
			if (dataSourceKeyMap.get(i) == null || dataSourceKeyMap.get(i).size() == 0) {
				throw new IllegalArgumentException("dataSourceKeyMap key must be serial num start with zero, each dataSources must not be null and size big than zero");
			}
		}
		this.dataSourceKeyMap = dataSourceKeyMap;
	}

}